fix(coding-agent): evict empty drafts when the last direct viewer detaches (ENG-5831) - #1946
Merged
Merged
Conversation
…aches Direct-transport clients attach and detach on the worker socket, so the supervisor-socket cleanup that owns empty-session eviction never saw their last detach and empty drafts lingered until an idle sweep. The worker already reports the drop: its peer attach/detach roster flush delivers a summary whose directAttachedClients falls to zero, so the supervisor's roster write funnel now triggers the existing last-detach eviction on that transition — covering both clean detach and unclean socket drop, which share the worker's detach path. The eviction candidate check counts direct viewers through the shared attachment sum, so a remaining direct client blocks a routed client's last detach and vice versa. Fixes ENG-5831.
xeophon
approved these changes
Sep 1, 2026
olety
added a commit
to oneiron-dev/prime-agent
that referenced
this pull request
Sep 1, 2026
Takes upstream's event-driven supervisor roster ledger + push (PrimeIntellect-ai#1897, PrimeIntellect-ai#1900), direct TUI<->worker transport (ENG-5817), daemon startup/recovery hardening (PrimeIntellect-ai#1929, PrimeIntellect-ai#1909), single-dump kernel snapshots (PrimeIntellect-ai#1945), empty-draft eviction (PrimeIntellect-ai#1946), rlm_child_update suppression (PrimeIntellect-ai#1944), bash-skill preview (PrimeIntellect-ai#1911). Fork laws re-expressed on the roster architecture: - stable-target follow-up honesty kept (capability proof via worker hello, target_unavailable never not_found when ownership unproven) - schema revision 26 (union of fork rev-24 stable-target + upstream rev-24/25 roster+transport); digest minted by the repo's own algorithm - summary freshness reuse + single-flight + staleness + root-omission rejection restored on upstream's refresh pull - adoption/recovery never fails a live worker on a slow or root-omitting catalog: get_state root seed + stale mark + bounded background rehydration - repl.py keeps fork prune-on-aggregate-overflow - delete handlers keep fork persistence reporting; eviction fence test keeps the stronger two-worker contention variant Known test debt (deferred to post-Wave cleanup per owner): roster-era fixture migrations in daemon-supervisor-monitor (2), plus un-triaged failures in package-command-paths, agent-session-recursion, daemon-runtime-stress, 4600-supervisor-singleton, 4603-worker-recovery, 4606-update-restart- coordinator, agents-view-roster. Production laws preserved; failures are fixture-era artifacts or mechanism assertions to rewrite.
ketema
added a commit
to ketema/prime-agent
that referenced
this pull request
Sep 1, 2026
- Direct session transport between TUI and worker (ENG-5817, PrimeIntellect-ai#1926) - Event-driven supervisor agent roster with push subscriptions (PrimeIntellect-ai#1897, PrimeIntellect-ai#1900, PrimeIntellect-ai#1895) - Hardened daemon startup, recovery ownership, and worker launch diagnostics (PrimeIntellect-ai#1929, PrimeIntellect-ai#1918) - Python REPL runtime single-dump snapshots and bash preview tool (PrimeIntellect-ai#1945, PrimeIntellect-ai#1911) - Non-blocking RLM subagent deletion and snapshot update suppression (PrimeIntellect-ai#1954, PrimeIntellect-ai#1944) - Saved catalog loading on Agents View open (PrimeIntellect-ai#1960) - Advanced Anthropic prompt caching marker across tool results (PrimeIntellect-ai#1927) - TUI process replacement on update and empty draft eviction (PrimeIntellect-ai#1631, PrimeIntellect-ai#1946, PrimeIntellect-ai#1920)
paralin
pushed a commit
to paralin/prime-agent
that referenced
this pull request
Sep 2, 2026
…aches (PrimeIntellect-ai#1946) Direct-transport clients attach and detach on the worker socket, so the supervisor-socket cleanup that owns empty-session eviction never saw their last detach and empty drafts lingered until an idle sweep. The worker already reports the drop: its peer attach/detach roster flush delivers a summary whose directAttachedClients falls to zero, so the supervisor's roster write funnel now triggers the existing last-detach eviction on that transition — covering both clean detach and unclean socket drop, which share the worker's detach path. The eviction candidate check counts direct viewers through the shared attachment sum, so a remaining direct client blocks a routed client's last detach and vice versa. Fixes ENG-5831.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Starting the TUI and quitting right away leaves the empty draft session behind as a zombie row in the agents view until an idle sweep catches it, if one ever runs (ENG-5831).
The empty-draft eviction from #1920 runs when the supervisor sees a client's last detach: on a supervisor socket close it walks that socket's attached sessions and evicts abandoned empty drafts. #1926 moved attach and detach onto the direct worker transport, so the session's viewer now attaches and detaches on the worker's own socket. The supervisor socket never records the attachment, its close-time walk finds nothing, and a clean quit does not touch the supervisor at all.
Fix
The worker already reports the exact signal: since #1926 it flushes a roster update when a direct viewer attaches or detaches, and that summary carries
directAttachedClients. Both exit paths produce it — a cleandetachcommand and an unclean socket drop share the worker's detach path.The supervisor's roster write funnel now triggers the existing last-detach eviction when a worker-reported summary's
directAttachedClientsdrops to zero. The eviction candidate check also counts direct viewers through the shared attachment sum, so with one routed and one direct client the session is evicted only when the last of both is gone, in either order.No new wire frames, timers, or sweep changes: the fix reuses the roster signal and the eviction path that already exist.
Validation
daemon-supervisor-eviction.test.ts: a worker-reported drop to zero direct viewers evicts an empty draft; a mixed routed+direct session evicts only after the last of both detaches.daemon-peer-transport,agent-connection-daemon,daemon-supervisor-monitor, anddaemon-routed-clientsuites all green with sanitized env.npm run checkgreen.Linear: ENG-5831
Note
Evict empty drafts when last direct-attached viewer detaches in
DaemonSupervisorevictable-empty-workercheck to useattachedClientCountso it accounts for both supervisor-routed and direct-attached clients when deciding if a worker is evictablewriteRosterEntry, detects when a worker'sdirectAttachedClientstransitions from >0 to 0 and triggersevictEmptySessionOnLastDetach, aligning direct-transport detach behavior with supervisor-routed clientsMacroscope summarized 2f879e6.
Note
Medium Risk
Touches daemon session eviction and roster-driven lifecycle, but reuses existing eviction helpers and is covered by new unit tests rather than new wire protocol.
Overview
Fixes empty draft sessions sticking around in the agents list after a user opens the TUI and quits immediately, because viewers on the direct worker transport no longer detach through the supervisor socket.
When a worker roster update shows
directAttachedClientsdropping from above zero to zero,writeRosterEntrynow runs the sameevictEmptySessionOnLastDetachpath used for supervisor-routed clients (clean detach or socket drop both show up this way). The empty-worker eviction check usesattachedClientCountso routed and direct attachments are counted together—mixed sessions are only evicted after both kinds of viewer are gone.Adds eviction tests for last direct detach and routed+direct ordering; changelog note for ENG-5831.
Reviewed by Cursor Bugbot for commit 2f879e6. Bugbot is set up for automated code reviews on this repo. Configure here.